//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2013 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_AUTO_STRING_H_
#define _BUOLA_AUTO_STRING_H_

#include <buola/auto/traits.h>
#include <string>
#include <cwchar>
#include <cstring>
#include <algorithm>
#define UCHAR_TYPE char16_t

namespace buola {

///\addtogroup string
///@{

///\name Character encoding
//@{
///UTF-8
#define COD_UTF8        "UTF-8"
///ASCII
#define COD_ASCII       "ASCII"
///codepage 850
#define COD_CP850       "CP850"
///codepage 437
#define COD_CP437       "CP437"
///ISO 8859-1
#define COD_ISO8859_1   "ISO8859-1"

///encodes an array of wide characters
std::string encode(const wchar_t *pSrc,size_t pLen,const char *pCod=COD_UTF8);
std::string encode(const wchar_t *pSrc,const char *pCod=COD_UTF8);

///encodes a wide string
inline std::string encode(const std::wstring &pStr,const char *pCod=COD_UTF8)
{
    return encode(pStr.data(),pStr.length(),pCod);
}

std::string utf8(const char16_t *pSrc,size_t pLen);
std::string utf8(const char16_t *pSrc);

inline std::string utf8(const std::u16string &pSrc)
{
    return utf8(pSrc.data(),pSrc.length());
}

std::string utf8(const wchar_t *pSrc,size_t pLen);
std::string utf8(const wchar_t *pSrc);

inline std::string utf8(const std::wstring &pSrc)
{
    return utf8(pSrc.data(),pSrc.length());
}

std::u16string utf16(const char *pSrc,size_t pLen);
std::u16string utf16(const char *pSrc);

inline std::u16string utf16(const std::string &pSrc)
{
    return utf16(pSrc.data(),pSrc.length());
}

std::u16string utf16(const wchar_t *pSrc,size_t pLen);
std::u16string utf16(const wchar_t *pSrc);

inline std::u16string utf16(const std::wstring &pSrc)
{
    return utf16(pSrc.data(),pSrc.length());
}

std::wstring utf32(const char *pSrc,size_t pLen);
std::wstring utf32(const char *pSrc);

inline std::wstring utf32(const std::string &pSrc)
{
    return utf32(pSrc.data(),pSrc.length());
}

std::wstring utf32(const char16_t *pSrc,size_t pLen);
std::wstring utf32(const char16_t *pSrc);

inline std::wstring utf32(const std::u16string &pSrc)
{
    return utf32(pSrc.data(),pSrc.length());
}

///decodes an array of characters
std::wstring decode(const char *pSrc,size_t pLen,const char *pCod=COD_UTF8);
std::wstring decode(const char *pSrc,const char *pCod=COD_UTF8);

///decodes a string
inline std::wstring decode(const std::string &pStr,const char *pCod=COD_UTF8)
{
    return decode(pStr.data(),pStr.length(),pCod);
}

///transcodes an array of characters
std::string transcode(const char *pSrc,size_t pLen,const char *pFrom,const char *pTo=COD_UTF8);
std::string transcode(const char *pSrc,const char *pFrom,const char *pTo=COD_UTF8);

///transcodes a string
inline std::string transcode(const std::string &pStr,const char *pFrom,const char *pTo=COD_UTF8)
{
    return transcode(pStr.data(),pStr.length(),pFrom,pTo);
}

//@}

///\name Formatting
//@{

///converts a byte array to a hexadecimal string
std::string hex_string(const uint8_t *pData,size_t pSize);

///converts a byte array to a hexadecimal wstring
std::wstring hex_wstring(const uint8_t *pData,size_t pSize);

template<typename tUInt>
OEnableIf<std::is_unsigned<tUInt>,std::string> hex_string(tUInt pUInt)
{
    uint8_t *lNumber=reinterpret_cast<uint8_t*>(&pUInt);
    uint8_t lBuffer[sizeof(pUInt)];
    for(int i=0;i<sizeof(pUInt);i++)
        lBuffer[i]=lNumber[sizeof(pUInt)-i-1];
    return hex_string(lBuffer,sizeof(pUInt));
}

///generates a string using printf-style formatting
///
///\param pFormat the format string. Look at the printf documentation for more information
std::string str_printf(const char *pFormat,...);

///generates a string using printf-style formatting
///
///\param pFormat the format string. Look at the printf documentation for more information
std::string str_printf(const std::string &pFormat,...);

///generates a string using printf-style formatting
///
///\param pFormat the format string. Look at the printf documentation for more information
std::wstring wstr_printf(const wchar_t *pFormat,...);

///generates a string using printf-style formatting
///
///\param pFormat the format string. Look at the printf documentation for more information
std::wstring wstr_printf(const std::wstring &pFormat,...);

///returns a string containing the same characters as the array
///
///the length of the string is the same as the array or the number of characters until the first
///'\0', whichever is smaller
template<typename tChar,size_t vLength>
std::basic_string<tChar> bounded_string(const tChar (&pArray)[vLength])
{
    return std::basic_string<tChar>(pArray,std::find(pArray,pArray+vLength,(tChar)0));
}

//@}

///\name Internationalization
//@{

///returns the string \p pStr internationalized with \c gettext
std::string I18N(const char *pStr);

///returns the string \p pStr internationalized with \c gettext (wide-string version)
std::wstring WI18N(const char *pStr);

//@}

///@}

/*namespace buola*/ }

#endif
